//
//  RACSignalTests.m
//  ZZRAC
//
//  Created by 赵梁 on 2018/11/2.
//  Copyright © 2018 layzhao. All rights reserved.
//

#import <XCTest/XCTest.h>

#import <ReactiveObjC.h>
#import "Person.h"

@interface RACSignalTests : XCTestCase

@end

@implementation RACSignalTests

- (void)setUp {
    // Put setup code here. This method is called before the invocation of each test method in the class.
}

- (void)tearDown {
    // Put teardown code here. This method is called after the invocation of each test method in the class.
}

- (void)testsignal
{
    
}

//2、bind 包装
//
//获取到信号返回的值，包装成新值, 再次通过信号返回给订阅者

- (void)testBind
{
    Person *person = [Person new];
    person.age = 6;
    [[RACObserve(person, age) bind:^RACSignalBindBlock _Nonnull{ return ^RACSignal*(id value, BOOL *stop) {
        // 处理完成之后，包装成信号返回出去
        return [RACSignal return:[NSString stringWithFormat:@"hello: %@",value]];
    };
    }] subscribeNext:^(id  _Nullable x) {
        NSLog(@"bind : %@",x); // hello: "x"
    }];
    
    person.age = 7;
    person.age = 8;
}

//3、concat 合并
//按一定顺序拼接信号，当多个信号发出的时候，有顺序的接收信号
- (void)testconcat
{
    RACSignal *signalA = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        NSLog(@"sendNext signalA");
        [subscriber sendNext:@"signalA"];
        [subscriber sendCompleted];
        return nil;
    }];
    RACSignal *signalB = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        NSLog(@"sendNext signalB");
        [subscriber sendNext:@"signalB"];
        [subscriber sendCompleted];
        return nil;
    }];
    // 把signalA拼接到signalB后，signalA发送完成，signalB才会被激活 顺序执行
    [[signalA concat:signalB] subscribeNext:^(id  _Nullable x) {
        //先拿到 signalA 的结果 ， 再拿到 signalB 的结果 ， 执行两次
        NSLog(@"concat result = %@", x);
    }];
}


//4、then 下一个
//
//用于连接两个信号，当第一个信号完成，才会连接then返回的信号
- (void)testthen
{
    // 底层实现  1.使用concat连接then返回的信号  2.先过滤掉之前的信号发出的值
    [[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        NSLog(@"1 : %@", subscriber);
        [subscriber sendNext:@1];
        [subscriber sendCompleted];
        return nil;
    }] then:^RACSignal *{
        return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            //可以对第一个信号的数据进行过滤处理 , 不能直接获得第一个信号的数据返回值
            NSLog(@"2 : %@", subscriber);
            [subscriber sendNext:@2];
            [subscriber sendCompleted];
            return nil;
        }];
    }] subscribeNext:^(id x) {
        // 只能接收到第二个信号的值，也就是then返回信号的值
        NSLog(@"then : %@",x); // 2
    }];
}

//5、merge 合并
//
//把多个信号合并为一个信号，任何一个信号有新值的时候就会调用
// 与concat的区别 是concat第一信号 执行sendCompleted 下一个信号才执行
// merge 则不会 合并的信号不相互干扰执行
- (void)testmerge
{
    //创建多个信号
    RACSignal *mergeSignalA = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        NSLog(@"sendNext 1");
        [subscriber sendNext:@1];
//        [subscriber sendCompleted];
        return nil;
    }];
    RACSignal *mergeSignalB = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        NSLog(@"sendNext 2");
        [subscriber sendNext:@2];
//        [subscriber sendCompleted];
        return nil;
    }];
    // 合并信号,只要有信号发送数据，都能监听到.
    RACSignal *mergeSignal = [mergeSignalA merge:mergeSignalB];
    
    [mergeSignal subscribeNext:^(id x) {
        //每次获取单个信号的值
        NSLog(@"merge : %@",x);
    }];
}

//6、zipWith 压缩
//
//把两个信号压缩成一个信号，只有当两个信号都发出一次信号内容后,并且把两个信号的内容合并成一个元组，才会触发压缩流的next事件(组合的数据都是一一对应的)
- (void)testzipWith
{
    RACSignal *zipSignalA = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        NSLog(@"sendNext 1");
        [subscriber sendNext:@1];
//        [subscriber sendCompleted];
        NSLog(@"sendNext 2");
        [subscriber sendNext:@2];
//        [subscriber sendCompleted];
        return nil;
    }];
    RACSignal *zipSignalB = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        //3秒后执行
//        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"sendNext 3");
            [subscriber sendNext:@3];
//            [subscriber sendCompleted];
//        });
        //5秒后执行
//        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"sendNext 5");
            [subscriber sendNext:@5];
//            [subscriber sendCompleted];
//        });
        
        return nil;
    }];
    
    RACSignal *zipSignal = [zipSignalA zipWith:zipSignalB];
    
    [zipSignal subscribeNext:^(id  _Nullable x) {
        // x 是一个元祖
        RACTupleUnpack(NSNumber *a, NSNumber *b) = x;
        NSLog(@"zip with : %@   %@", a, b);
        //第一次输出   1  3
        //第二次输出   2  5
    }];
}


//7、combineLatest 结合
//将多个信号合并起来，并且拿到各个信号的最新的值,必须每个合并的signal至少都有过一次sendNext，才会触发合并的信号 (combineLatest 与 zipWith不同的是，每次只拿各个信号最新的值)
- (void)test_combineLatest
{
    RACSignal *combineSignalA = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@1];
        [subscriber sendNext:@2];
        return nil;
    }];
    
    RACSignal *combineSignalB = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
//        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [subscriber sendNext:@3];
//        });
//        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [subscriber sendNext:@5];
//        });
        
        return nil;
    }];
    
    RACSignal *combineSignal = [combineSignalA combineLatestWith:combineSignalB];
    
    [combineSignal subscribeNext:^(id  _Nullable x) {
        // x 是一个元祖
        RACTupleUnpack(NSNumber *a, NSNumber *b) = x;
        NSLog(@"combineLatest : %@   %@", a, b);
        //第一次输出 2 3
        //第二次输出 2 5
        //因为combineSignalA中的2是最新数据，所以，combineSignalA每次获取到的都是2
    }];
}

//8、reduce 聚合
//
//用于信号发出的内容是元组，把信号发出元组的值聚合成一个值，一般都是先组合在聚合
- (void)test_reduce
{
    RACSignal *reduceSignalA = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@1];
        return nil;
    }];
    
    RACSignal *reduceSignalB = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@3];
        return nil;
    }];
    
    RACSignal *reduceSignal = [RACSignal combineLatest:@[reduceSignalA, reduceSignalB] reduce:^id(NSNumber *a, NSNumber *b) {
        //reduce中主要是对返回数据的处理
        return [NSString stringWithFormat:@"%@ - %@", a, b];
    }];
    
    [reduceSignal subscribeNext:^(id  _Nullable x) {
        //返回值x 取决于reduce之后的返回
        NSLog(@"reduce : %@", x);
    }];
}

//9、map 数据过滤
//map 的底层实现是通过flattenMap 实现的。map 直接对数据进行处理，并且返回处理后的数据
- (void)test_map
{
    Person *person = [Person new];
//    person.age = 100;
    [[RACObserve(person, age) map:^id _Nullable(NSString * _Nullable value) {
        // 当源信号发出，就会调用这个block，修改源信号的内容
        // 返回值：就是处理完源信号的内容。
        return [NSString stringWithFormat:@"hello : %@",value];
    }] subscribeNext:^(id  _Nullable x) {
        NSLog(@"Map : %@",x); // hello: "x"
    }];
//    person.age = 20;
}


//10、flattenMap 信号过滤
//flattenMap 的底层实现是通过bind实现的。拿到原数据，处理完成之后，包装成信号返回
- (void)test_flattenMap
{
    Person *person = [Person new];
    //    person.age = 100;
    [[RACObserve(person, age) flattenMap:^__kindof RACSignal * _Nullable(NSString * _Nullable value) {
        return  [RACSignal return:[NSString stringWithFormat:@"hello : %@", value]];
    }] subscribeNext:^(id  _Nullable x) {
        NSLog(@"flattenMap : %@", x); // hello "x"
    }];
}

//10、filter 过滤
//过滤信号，获取满足条件的信号
- (void)test_filter
{
    Person *person = [Person new];
    person.age = 16;
    [[RACObserve(person, age) filter:^BOOL(NSNumber *value) {
        return value.integerValue > 6;
    }] subscribeNext:^(NSString * _Nullable x) {
        NSLog(@"filter ： %@", x); // x 值位数大于6
    }];
    person.age = 100;
    person.age = 2;
}

- (void)test_1
{
    
}
- (void)testsignal1
{
    
}
@end
